import time
import os
import subprocess
import multiprocessing
from multiprocessing import Pool
from functools import partial
from openpyxl import load_workbook
from Microservice_Managers.frontend import *
from Microservice_Managers.adservice import *
from Microservice_Managers.checkoutservice import *
from Microservice_Managers.currencyservice import *
from Microservice_Managers.emailservice import *
from Microservice_Managers.paymentservice import *
from Microservice_Managers.productcatalogservice import *
from Microservice_Managers.cartservice import *
from Microservice_Managers.recommendationservice import *
from Microservice_Managers.shippingservice import *
from Microservice_Managers.rediscart import *
from Adaptive_Resource_Manager import *

# folder_name = '20'
folder_name = '50'
# folder_name = '80'

def Execute(microservice_name, desired_replicas):
    """执行扩容或缩容命令"""
    execute_command = f"kubectl scale deployment {microservice_name} -n boutique --replicas={desired_replicas}"
    print(f"Executing command: {execute_command}")
    os.system(execute_command)
    return

def run_function(func):
    """运行微服务管理器，并打印结果"""
    result = func()
    print(f"Running function {func.func.__name__}, result: {result}")
    return result

# Smart HPA 的操作逻辑
desired_time = 900  # Total_Test_Time (sec)
start_time = time.time()

if __name__ == '__main__':
    ARM_saved_decision = []  # 上一次 ARM 的伸缩决策
    row_number = 2  # Excel 中存储结果的行数

    while (time.time() - start_time) < desired_time:
        Test_Time = time.time() - start_time
        print(f"\nRunning test cycle at {Test_Time} seconds")

        # 并行运行各微服务管理器
        functions = [
            partial(frontend, Test_Time, folder_name), partial(adservice, Test_Time, folder_name),
            partial(cartservice, Test_Time, folder_name), partial(currencyservice, Test_Time, folder_name),
            partial(checkoutservice, Test_Time, folder_name), partial(emailservice, Test_Time, folder_name),
            partial(paymentservice, Test_Time, folder_name), partial(shippingservice, Test_Time, folder_name),
            partial(productcatalogservice, Test_Time, folder_name), partial(recommendationservice, Test_Time, folder_name),
            partial(rediscart, Test_Time, folder_name)
        ]
        
        with multiprocessing.Pool(processes=len(functions)) as pool:
            microservices_data = pool.map(run_function, functions)
            print(f"Collected microservices data: {microservices_data}")

        ARM_decision = []  # 当前的伸缩决策

        # 分析每个微服务的资源使用情况
        for i, service_data in enumerate(microservices_data):
            if len(service_data) < 6:
                print(f"Warning: Insufficient data for microservice {service_data[0]}, skipping.")
                continue

            # 检查是否超出最大副本数限制
            if service_data[2] > service_data[5]:  # 期望副本数 > 最大副本数
                print(f"Resource constraint detected for microservice: {service_data[0]}")
                
                # 更新 maxR 以便 ARM 决策
                for k in range(len(microservices_data)):
                    for j, decision in enumerate(ARM_saved_decision):
                        if microservices_data[k][0] == decision[0]:
                            microservices_data[k][5] = decision[3]  # 更新 maxR
                            print(f"Updated max replicas for {microservices_data[k][0]} to {microservices_data[k][5]}")
                
                # 调用 ARM 进行伸缩决策
                ARM_decision = Adaptive_Resource_Manager(microservices_data)
                print(f"ARM decision: {ARM_decision}")
                ARM_saved_decision = ARM_decision
                break  # 找到一个受限服务后退出循环，ARM 已经处理所有服务的决策

        processes = []
        
        # 资源丰富的情况
        if len(ARM_decision) == 0:
            print("Resource-rich environment, no constraints detected.")
            ARM_saved_decision = microservices_data  # 用当前数据更新决策保存
            for service_data in microservices_data:
                filename = service_data[0]
                file_path = f'/root/wmxstudy/Smart_HPA/Smart_HPA_Codebase/Knowledge_Base/{folder_name}/{filename}.xlsx'
                workbook = load_workbook(file_path)
                sheet = workbook.active
                sheet.cell(row=row_number, column=5, value=service_data[5])  # Maximum replicas
                sheet.cell(row=row_number, column=6, value=service_data[1])  # Scaling decision
                workbook.save(file_path)

                # 执行扩缩容操作
                if service_data[1] != "no scale":
                    print(f"Scaling microservice {service_data[0]} to {service_data[2]} replicas")
                    process = multiprocessing.Process(target=Execute, args=(service_data[0], service_data[2]))
                    processes.append(process)
                    process.start()

            for process in processes:  # 等待所有进程完成
                process.join()
        
        # 资源受限的情况
        else:
            print("Resource-constrained environment detected.")
            for decision in ARM_decision:
                filename = decision[0]
                file_path = f'/root/wmxstudy/Smart_HPA/Smart_HPA_Codebase/Knowledge_Base/{folder_name}/{filename}.xlsx'
                workbook = load_workbook(file_path)
                sheet = workbook.active
                sheet.cell(row=row_number, column=5, value=decision[3])  # 更新最大副本数
                sheet.cell(row=row_number, column=6, value=decision[1])  # 伸缩决策
                workbook.save(file_path)

                # 执行伸缩决策
                if decision[1] != "no scale":
                    print(f"Scaling microservice {decision[0]} to {decision[2]} replicas")
                    process = multiprocessing.Process(target=Execute, args=(decision[0], decision[2]))
                    processes.append(process)
                    process.start()

            for process in processes:  # 等待所有进程完成
                process.join()

        row_number += 1
        
        print("Current ARM decision:", ARM_decision)